import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/cupertino.dart';
import 'chat_result_entity.dart';
import 'controller_stream.dart';
import 'record_util.dart';
import 'sound_util.dart';
import 'speex_ffi.dart';

class AiDeviceVoiceControllerManager {
  /// 单例实例：全局唯一的语音控制管理器
  /// 通过私有构造函数 + 静态常量实例，强制外部只能通过 `instance` 访问，避免多实例导致的资源冲突
  static final AiDeviceVoiceControllerManager instance = AiDeviceVoiceControllerManager._();

  /// 私有构造函数：禁止外部通过 `new AiDeviceVoiceControllerManager()` 创建实例，保障单例唯一性
  AiDeviceVoiceControllerManager._();

  /// Speex 解码器实例：用于将服务端返回的 Speex 压缩音频解码为 PCM 原始音频（供播放使用）
  /// 与 `RecordUtil` 中的 Speex 编码器对应，确保编码/解码格式一致
  final _decoder = SpeexDecoderFFI();

  /// 初始化状态标记：true 表示已完成录音器、播放器的初始化，false 表示未初始化
  /// 用于避免重复调用初始化方法，减少资源消耗
  bool _isInit = false;

  /// 初始化核心组件：初始化录音器（RecordUtil）和播放器（SoundUtil）
  /// 【注意】需在调用 `start()` 前执行（`start()` 内部会自动调用，外部可省略）
  /// @return 无返回值，通过 Future 标识初始化完成状态
  init() async {
    // 仅当未初始化时执行，避免重复初始化
    if (!_isInit) {
      debugPrint("初始化录音器（RecordUtil）和播放器（SoundUtil）");
      // 初始化录音器：打开底层麦克风设备，为后续录音做准备
      await RecordUtil.instance.initRecorder();
      // 初始化播放器：打开底层扬声器设备，为后续音频播放做准备
      await SoundUtil.instance.initPlayer();
      // 更新初始化状态，标记为已完成
      _isInit = true;
    }
  }

  /// 启动语音交互流程：整合“录音→编码→传输→接收→解码→播放→结果回调”全链路
  /// @param callback：语音交互结果回调函数，返回 `VoiceControllerResult` 类型（包含ASR文本、TTS文本、错误信息）
  /// @return 无返回值，通过 Future 标识启动流程完成
  start(Function(VoiceControllerResult) callback) async {
    debugPrint("启动语音交互流程");
    // 确保核心组件已初始化（若未初始化则自动执行 init()）
    await init();
    await stopAll();

    // 初始化语音交互结果对象：存储ASR（语音转文字）、TTS（文字转语音）结果和错误信息
    VoiceControllerResult result = VoiceControllerResult(asr: "", tts: "", speedInputState: SpeedInputState.ide);
    // 监听 WebSocket 通道的服务端响应：处理服务端返回的各类结果（ASR/TTS/音频/错误）
    ControllerChannel.instance.listen((ChatResultEntity res) {
      // 1. 处理 ASR 文本结果（服务端返回语音转文字的文本）
      if (res.metadata?.responseType == "ASR_TEXT") {
        // 将服务端返回的文本赋值给结果对象，若为null则设为空字符串
        result.asr = res.payload?.text ?? "";
        result.speedInputState = SpeedInputState.asrIng;
      }
      // 2. 处理 TTS 文本结果（服务端返回文字转语音的原始文本）
      else if (res.metadata?.responseType == "TTS_TEXT") {
        // 累加 TTS 文本（支持多段文本拼接，如长句子分批次返回）
        result.tts += (res.payload?.text ?? "");
        result.speedInputState = SpeedInputState.recognizing;

      }
      // 3. 处理音频数据（服务端返回的 Speex 压缩音频，需解码后播放）
      else if (res.metadata?.responseType == "AUDIO") {
        result.speedInputState = SpeedInputState.recognizing;
        // 步骤1：将服务端返回的 Base64 编码音频字符串解码为字节数组
        Uint8List bytes = base64.decode(res.payload!.audio!);
        // Speex 音频帧大小：固定60字节（需与服务端编码时的帧大小一致，否则解码失败）
        int frameSize = 60;
        // 字节数组偏移量：用于循环截取每帧数据
        int offset = 0;

        // 循环截取每帧 Speex 数据并解码
        while (offset + frameSize <= bytes.length) {
          // 截取单帧 Speex 数据（从offset开始，长度为frameSize）
          final frame = bytes.sublist(offset, offset + frameSize);
          // 更新偏移量，准备截取下一帧
          offset += frameSize;
          // 将 Speex 帧解码为 PCM 原始音频（供播放器使用）
          final pcmFrame = _decoder.decode(frame);
          // 将 PCM 数据喂给播放器，实时播放音频
          SoundUtil.instance.feedAudioChunk(pcmFrame);
        }

        // 若服务端标记音频传输结束（status=2 对应尾帧），则停止播放器
        if (res.payload?.status == ControllerChannel.lastFrame) {
          SoundUtil.instance.stopStreamPlayer();
        }
      }
      // 4. 处理错误结果（服务端返回交互失败信息）
      else if (res.metadata?.responseStatus == "ERROR" && res.metadata?.responseType == "COMPLETE") {
        // 将服务端返回的错误信息赋值给结果对象，若为null则设为空字符串
        result.errorMessage = res.payload?.message ?? "";
        result.speedInputState = SpeedInputState.ide;
      }

      // 将最新的交互结果通过回调返回给外部业务层（如UI展示ASR文本、处理错误）
      callback(result);
    });

    // 启动录音并监听录音数据：将录音编码后的 Speex 数据通过 WebSocket 发送给服务端
    await RecordUtil.instance.listen((Uint8List data, int status) async {
      // 调用 WebSocket 通道发送音频数据（data=Speex编码数据，status=帧状态）
      await ControllerChannel.instance.send(data, status, onDone: () {
        result.speedInputState = SpeedInputState.ide;
        callback(result);
        stopAll();
      });
    }, onError: (e) {
      result.speedInputState = SpeedInputState.ide;
      callback(result);
      stopAll();
    });
  }

  /// 停止录音操作：仅终止录音流程，不影响播放器和 WebSocket 连接
  /// 适用于“仅停止说话，仍需接收服务端后续响应（如TTS播放）”的场景
  /// @return 无返回值，通过 Future 标识停止操作完成
  stop() async {
    debugPrint("停止录音 - stop");
    // 调用录音工具类的停止方法，终止麦克风采集
    await RecordUtil.instance.stopRecord();
    await ControllerChannel.instance.send(null, ControllerChannel.lastFrame);
  }

  /// 终止所有语音交互操作：停止录音、停止播放、关闭 WebSocket 连接
  /// 适用于“完全结束语音交互”的场景（如用户取消操作、交互流程完成）
  /// @return 无返回值，通过 Future 标识所有操作终止完成
  stopAll() async {
    debugPrint("终止所有语音交互操作 - stopAll");
    // 1. 停止录音：释放麦克风资源
    await RecordUtil.instance.stopRecord();
    // 2. 停止播放：释放扬声器资源，终止当前音频输出
    await SoundUtil.instance.stopStreamPlayer();
    // 3. 关闭 WebSocket 连接：终止与服务端的通信，释放网络资源
    await ControllerChannel.instance.stop();
  }
}

enum SpeedInputState {
  ide, /// 准备就绪
  asrIng, /// 监听中
  recognizing, /// 识别中
  complete
}

class VoiceControllerResult {
  /// ASR 结果：语音转文字的文本（如用户说话内容的识别结果）
  String asr;

  /// TTS 结果：文字转语音的原始文本（如服务端返回的待合成语音文本）
  String tts;

  /// 错误信息：语音交互过程中出现的错误描述（如网络异常、服务端识别失败）
  ///  nullable 类型，无错误时为 null
  String? errorMessage;

  SpeedInputState speedInputState;

  /// 构造函数：初始化 ASR 和 TTS 为默认空字符串，错误信息可选（默认 null）
  /// @param asr：初始 ASR 文本（必填，默认空字符串）
  /// @param tts：初始 TTS 文本（必填，默认空字符串）
  /// @param errorMessage：初始错误信息（可选，默认 null）
  VoiceControllerResult({
    required this.asr,
    required this.tts,
    required this.speedInputState,
    this.errorMessage,
  });

  /// （可选扩展）重写 toString 方法：方便调试时打印结果信息
  @override
  String toString() {
    return 'VoiceControllerResult{asr: $asr, tts: $tts, speedInputState: $speedInputState, errorMessage: $errorMessage}';
  }

  /// （可选扩展）重置结果：用于多轮交互场景，清空上一轮的结果
  void reset() {
    asr = "";
    tts = "";
    errorMessage = null;
  }
}